package com.riteny;

import com.riteny.util.exception.ExceptionHandlerAgent;
import com.riteny.util.exception.datasource.ProfileSource;
import com.riteny.util.exception.entity.CommonException;
import com.riteny.util.exception.entity.RestResponseTemplate;
import com.riteny.util.exception.handler.CustomExceptionHandler;
import com.riteny.util.exception.properties.InternationalizationProfile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author Riteny
 * 2019/11/25  14:07
 */
@ControllerAdvice
public class ApiCommonExceptionHandler {

    private Logger logger = LoggerFactory.getLogger(ApiCommonExceptionHandler.class);

    @Autowired
    public ApiCommonExceptionHandler(ProfileSource profileSource) {
        profileSource.initErrorCodeProfile();
    }

    @ExceptionHandler(value = CommonException.class)
    @ResponseBody
    public RestResponseTemplate<String> CommonExceptionHandler(HttpServletRequest request, HttpServletResponse response, CommonException e) {

        //檢查該類型是否配置了特殊的異常處理流程
        CustomExceptionHandler customExceptionHandler = ExceptionHandlerAgent.getHandler(e);
        if (customExceptionHandler != null) {
            customExceptionHandler.beforceHandler(request, response, e);
        }

        /*
         * 該工具可用於對異常信息進行國際化並統一返回，但也可以當成普通異常攔截器使用
         * 所以會檢查是否傳入了語言國際化參數
         * 如果有，運行工具國際化異常處理流程，沒有則獲取對應的異常代碼，異常消息，並返回統一格式的返回對象
         */
        RestResponseTemplate<String> restResponseTemplate;
        String langType = request.getHeader("lang");
        if (StringUtils.isEmpty(langType)) {
            //沒有國際化參數，返回普通的返回對象
            restResponseTemplate = new RestResponseTemplate<>(e.getErrorCode(), e.getErrorMsg(), null);
        } else {
            //進入異常信息國際化流程
            String errorMsg = InternationalizationProfile.getProfile(langType, e.getErrorCode());

            if (StringUtils.isEmpty(errorMsg)) {
                //語言參數已經傳遞，但在配置文件中并沒有找到對應異常編碼的異常消息内容
                restResponseTemplate = new RestResponseTemplate<>(e.getErrorCode(), e.getErrorMsg(), null);
            } else {
                //返回國際化后的異常消息内容
                restResponseTemplate = new RestResponseTemplate<>(e.getErrorCode(), errorMsg, null);
            }
        }

        //檢查該類型是否配置了特殊的異常處理流程
        if (customExceptionHandler != null) {
            customExceptionHandler.afterHandler(request, response, restResponseTemplate, e);
        }

        return restResponseTemplate;
    }

    /**
     * 處理通用異常，該異常通常為意料之外的問題
     *
     * @param request request
     * @param e       異常處理對象
     * @return
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public RestResponseTemplate exceptionHandler(HttpServletRequest request, Exception e) {
        logger.error(e.getMessage(), e);
        RestResponseTemplate restResponseTemplate = new RestResponseTemplate<String>(CommonException.STATUS_ERROR, "url : " + request.getRequestURL().toString() + "   method : " + request.getMethod() + "  IP : " + request.getRemoteAddr()
                + "Error msg :" + e.getMessage(), null);
        logger.error("url : " + request.getRequestURL().toString() + "   method : " + request.getMethod() + "  IP : " + request.getRemoteAddr() + " response : " + restResponseTemplate);
        return restResponseTemplate;
    }
}
